package ac.biu.nlp.nlp.curator.client;


import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Stack;

import org.apache.thrift.TException;
import org.apache.thrift.protocol.TBinaryProtocol;
import org.apache.thrift.protocol.TProtocol;
import org.apache.thrift.transport.TFramedTransport;
import org.apache.thrift.transport.TSocket;
import org.apache.thrift.transport.TTransport;
import org.w3c.dom.Document;
import org.w3c.dom.Element;

import edu.illinois.cs.cogcomp.thrift.base.AnnotationFailedException;
import edu.illinois.cs.cogcomp.thrift.base.Node;
import edu.illinois.cs.cogcomp.thrift.base.ServiceUnavailableException;
import edu.illinois.cs.cogcomp.thrift.base.Tree;
import edu.illinois.cs.cogcomp.thrift.curator.Curator;
import edu.illinois.cs.cogcomp.thrift.curator.Record;


/**
 * 
 * @author Asher Stern
 * @since Mar 22, 2013
 *
 */
public class ClientTreesXml
{

	public ClientTreesXml(String host, int port)
	{
		super();
		this.host = host;
		this.port = port;
		
		constructTransport();
	}
	
	public void process(Document document, Element element, String text, List<String> annotators) throws ServiceUnavailableException, AnnotationFailedException, TException, CuratorClientException
	{
		if (annotators.size()<=0) throw new CuratorClientException("Zero items list of annotators");
		List<Record> records = new ArrayList<Record>(annotators.size());
		for (String annotator : annotators)
		{
			records.add(processText(text,annotator));
		}
		
		appendTrees(document,element,records,annotators);
	}

	/**
	 * Called by the constructor
	 */
	private void constructTransport()
	{
		transport = new TSocket(host, port);
		transport = new TFramedTransport(transport);
		TProtocol protocol = new TBinaryProtocol(transport);
		client = new Curator.Client(protocol);
	}
	
	private Record processText(String text, String annotatorName) throws ServiceUnavailableException, AnnotationFailedException, TException
	{
		Record record = null;
		transport.open();
		try
		{
			record = client.provide(annotatorName, text, false);
		}
		finally
		{
			transport.close();
		}
		return record;
	}
	
	private void appendTrees(Document document, Element element, List<Record> records, List<String> recordKeys) throws CuratorClientException
	{
		if (records.size()<=0) throw new CuratorClientException("zero items list of records.");
		Record firstRecord = records.iterator().next();
		String rawText = firstRecord.getRawText();
		Element rawTextElement = document.createElement("raw-text");
		rawTextElement.appendChild(document.createTextNode(rawText));
		element.appendChild(rawTextElement);
		Element treesElement = document.createElement("trees");
		element.appendChild(treesElement);

		Iterator<String> recordKeysIterator =  recordKeys.iterator();
		for (Record record : records)
		{
			String recordKey = recordKeysIterator.next();
			for (Tree depTree : record.getParseViews().get(recordKey).getTrees())
			{
				Element treeElement = document.createElement("tree");
				treesElement.appendChild(treeElement);

				int top = depTree.getTop(); //this tells us where in nodes the head node is
				Stack<Integer> stack = new Stack<Integer>();
				stack.push(top);
				while (!stack.isEmpty())
				{
					int headIndex = stack.pop();
					Node head = depTree.getNodes().get(headIndex);
					if (!head.isSetChildren())
					{
						continue;
					}
					Element treeNodeElement = document.createElement("node");
					treeElement.appendChild(treeNodeElement);
					Element treeNodeTextElement = document.createElement("span");
					treeNodeElement.appendChild(treeNodeTextElement);
					treeNodeTextElement.appendChild(
							document.createTextNode(record.getRawText().substring(head.getSpan().getStart(), head.getSpan().getEnding()))
							);

					Element childrenElement = document.createElement("children");
					treeNodeElement.appendChild(childrenElement);

					for (Integer childIndex : head.getChildren().keySet())
					{
						stack.push(childIndex);
						Node child = depTree.getNodes().get(childIndex);
						String relation = head.getChildren().get(childIndex);
						Element childElement = document.createElement("child");
						childElement.setAttribute("index", String.valueOf(childIndex));
						childElement.setAttribute("reltion", relation);
						childElement.appendChild(
								document.createTextNode(record.getRawText().substring(child.getSpan().getStart(), child.getSpan().getEnding()))
								);
						childrenElement.appendChild(childElement);
					}
				}
			}
		}
	}
	

	
	private final String host;
	private final int port;
	
	private TTransport transport;
	private Curator.Client client;
	
}

